<?php


namespace App\Services\Base;

use App\Constants\AuthType;
use App\Constants\VerifyCodeType;
use App\Exceptions\ApiException;
use App\Mail\SendCode;
use App\Services\Sms\Aliyun;
use App\Services\Sms\SmsTcby;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class CodeService
{
    private $auth_code_key = "auth_code_";
    private $last_send_key = "last_send_";
    protected $code;

    private $title;     //标题
    private $content;   //内容
    private $to;        //接收者
    private $type;      //发送类型

    public function getCode($identity)
    {
        $key = $this->auth_code_key . $identity;
        return CacheService::get($key);
    }

    public function checkCode($identity, $auth_code, $delete = true)
    {
        //判断验证码不需要验证
        $default_sms = config('comm.verify_code.default');
        if ($default_sms) {
            if ($default_sms == $auth_code)
                return true;
        }

        $key = $this->auth_code_key . $identity;
        $cache_code = CacheService::get($key);

        if (!$auth_code) {
            throw new \Exception("", 412); //请输入验证码
        }

        if ($cache_code != $auth_code) {
            if (!$cache_code) {
                throw new \Exception("", 413);
            } else {
                if ($delete) {
                    CacheService::del($key);
                    CacheService::del($this->last_send_key . $identity);
                }
                throw new \Exception("", 414);
            }
        }

        CacheService::del($key);
        CacheService::del($this->last_send_key . $identity);

        return true;

    }

    public function storeCode($identity)
    {
        $length = config('comm.verify_code.length') ?: 6;
        $this->code = g_generate_digital($length);
        $key = $this->auth_code_key . $identity;
        $expire = config('comm.verify_code.expired') ?: 10;
        CacheService::set($key, $this->code, $expire * 60); //10分钟
        return $this->code;
    }

    public function checkLimit($identity, $lang = '')
    {
        $wait_time = (config('comm.verify_code.wait_send') ?: 1) * 60;
        $key = $this->last_send_key . $identity;
        $value = CacheService::get($key);
        if ($value) {
            $time = time() - $value;
            if ($time < $wait_time) {
                $wait = $wait_time - $time;
                throw new \Exception(trans('cs.sms_wait_time', ['wait' => $wait]), 500);
            }
        }
        CacheService::set($key, time(), $wait_time);
    }

    public function generateCode($identity, $lang = '')
    {
        $this->checkLimit($identity, $lang);
        return $this->storeCode($identity);
    }

    public function getIdentity($user_id, $device_id, $type)
    {
        return $user_id . '_' . $device_id . '_' . $type;
    }

    /**
     * @param $username //用户名
     * @param $device_id //设备id
     * @param $to //接收邮箱或者短信
     * @param $type //发送类型
     * @param $title //标题
     * @param int $send_type //1邮箱 2手机
     * @param string $name //短信平台名称
     * @param string $lang //语言
     * @return array|bool|string
     */
    public function send($username, $device_id, $to, $type, $title, $send_type = 1, $name = 'tcby', $lang = '')
    {
        $this->type = $type;
        if (array_key_exists($type, VerifyCodeType::$lib_type)) {
            $this->content = VerifyCodeType::$lib_type[$type];
        }

        $this->title = $title;
        $this->to = $to;
        $identity = $this->getIdentity($username, $device_id, $type);
        $this->generateCode($identity, $lang);

        $sendData = [
            "username" => $username,
            "code" => $this->code,
            "device_id" => $device_id,
            "to" => $to,
            "type" => $type,
            "title" => $title,
            "send_type" => $send_type,
            "name" => $name,
            "lang" => $lang
        ];
        Log::debug("code=>" . json_encode($sendData));
        if ($send_type == AuthType::CHECK_PHONE) {
            switch ($name) {
                case 'aliyun':
                    $service = new Aliyun();
                    if (!config('comm.sms.ali.accessKeyId')) {
                        throw new \Exception('', 1023);
                    }
                    return $service->send($this->to, $this->code);
                case 'tcby':
                    $service = new SmsTcby();
                    return $service->sendValidate($this->to, $this->code);
            }

        } else {
            try {
                if (!config('comm.email.title')) {
                    throw new \Exception('', 1022);
                }

                Mail::to($this->to)->send(new SendCode([
                    'info' => __($this->content, [], $lang) . ":" . $this->code,
                    'title' => config('comm.email.title')]));
                $error = Mail::failures();

                if ($error) {
                    return false;
                } else {
                    return true;
                }
            } catch (\Exception $e) {
                if ($e->getCode() == DEFAULT_CODE) {
                    throw new ApiException($e->getMessage());
                } else {
                    HelpService::forceLog($e);
                    return false;
                }
            }
        }
    }


}
